package server

import (
	"context"
	"errors"
	"github.com/google/uuid"
	"net/http"
	"sync"
	"ws-demo-go/pkg/logger"
	"ws-demo-go/pkg/ws/common"
	"ws-demo-go/pkg/ws/server"
)

const (
	ErrorConnID = "-2" // 发生错误时 Connection 的 connID
)

type Server struct {
	addr        string                 // 监听地址（如 ":8080"）
	connections map[string]*Connection // 管理所有客户端连接（key: 连接ID）
	mu          sync.RWMutex           // 保护 connections 并发安全
	hook        Hook                   // 传输层服务端启动时生命周期的一些钩子函数
	closeChan   chan struct{}          // 用于触发关闭的通道
}

// NewTransportServer 创建传输层服务端实例
func NewTransportServer(addr string) *Server {
	return &Server{
		addr:        addr,
		connections: make(map[string]*Connection),
	}
}

// Start 启动服务端，开始监听
func (ts *Server) Start() error {
	// 定义 handler
	mux := http.NewServeMux()
	mux.HandleFunc("/ws", ts.handleUpgrade) // 注册 WebSocket 升级路由

	// 创建 http.Server 实例
	srv := &http.Server{
		Addr:    ts.addr, // 监听地址
		Handler: mux,     // 处理器
	}

	// 启动一个监听退出信号的协程
	go ts.listenExitSignal(srv)

	// 启动服务器
	logger.Info("Server started on %s", ts.addr)
	err := srv.ListenAndServe()
	if err != nil && !errors.Is(err, http.ErrServerClosed) {
		logger.Error("Server start failed：%v", err)
		return err
	}
	return nil
}

// Stop 停止服务端，发送停止信号
func (ts *Server) Stop() {
	logger.Info("Stopping server")
	close(ts.closeChan)
}

// GetConnection 获取指定ID的连接
func (ts *Server) GetConnection(connID string) *Connection {
	ts.mu.RLock()
	defer ts.mu.RUnlock()
	return ts.connections[connID]
}

// GetAllConnections 获取所有连接
func (ts *Server) GetAllConnections() []*Connection {
	ts.mu.RLock()
	defer ts.mu.RUnlock()
	connections := make([]*Connection, 0, len(ts.connections))
	for _, conn := range ts.connections {
		connections = append(connections, conn)
	}
	return connections
}

// SetHook 设置回调
func (ts *Server) SetHook(hook Hook) {
	ts.hook = hook
}

// 监听退出信号，含有退出的逻辑
func (ts *Server) listenExitSignal(srv *http.Server) {
	// 监听中断信号，优雅关闭服务器
	ts.closeChan = make(chan struct{})
	<-ts.closeChan // 阻塞等待信号
	logger.Info("Server received exit signal, start to shutdown gracefully")

	// 设定关闭超时时间
	ctx, cancel := context.WithTimeout(context.Background(), common.ServerShutdownTimeout)
	defer cancel()

	// 优雅关闭服务器（Shutdown 会等待现有请求处理完成）
	if err := srv.Shutdown(ctx); err != nil {
		logger.Error("Server shutdown failed：%v", err)
	}
	logger.Info("Server shutdown gracefully")
}

// 处理客户端的 HTTP 升级请求
func (ts *Server) handleUpgrade(w http.ResponseWriter, r *http.Request) {
	wsConn, err := server.Upgrade(w, r)
	if err != nil {
		logger.Error("Upgrade failed:", err)
		return
	}

	// 创建服务端连接实例（带唯一ID）
	connID := generateConnID()
	conn := NewConnection(&wsConn, connID)

	// 设置 onMessage 回调
	conn.onMessage = ts.hook.OnMessage

	// 执行消息层 OnConnected 回调
	if onConnected := ts.hook.OnConnected; onConnected != nil {
		onConnected(conn)
	}

	// 将 conn 对象放到连接集合中
	ts.addConnection(conn)

	// 启动多个循环
	go conn.readLoop()
	go conn.writeLoop()
	go conn.checkPingLoop()

	// 在单独的 goroutine 中处理连接关闭事件
	go func() {
		// 等待连接关闭通知，无需轮询，这种基于通道的方式比轮询更高效，避免了不必要的CPU消耗
		<-conn.getClosedChan()

		// 执行消息层 OnDisconnected 回调
		if onDisconnected := ts.hook.OnDisconnected; onDisconnected != nil {
			onDisconnected(conn)
		}

		// 从连接集合中移除 conn 对象
		ts.removeConnection(connID)
	}()
}

// 将连接添加到连接管理器中
func (ts *Server) addConnection(conn *Connection) {
	ts.mu.Lock()
	defer ts.mu.Unlock()
	ts.connections[conn.connID] = conn
	logger.Info("Connection added, ID: %s", conn.connID)
}

// 从连接管理器中移除连接
func (ts *Server) removeConnection(connID string) {
	ts.mu.Lock()
	defer ts.mu.Unlock()
	if _, exists := ts.connections[connID]; exists {
		delete(ts.connections, connID)
		logger.Info("Connection removed, ID: %s", connID)
	}
}

// 生成唯一的连接ID
func generateConnID() string {
	var connID string
	u, err := uuid.NewRandom()
	if err != nil {
		logger.Info("generate UUID failed: %v, set connID to \"%s\"", err, ErrorConnID)
		connID = ErrorConnID
	} else {
		connID = u.String()
	}
	return "conn-" + connID
}
